package com.dronff.gvm.memorymanager.impl;

import com.dronff.gvm.entity.MiniAddress;
import com.dronff.gvm.interfaces.*;
import com.dronff.gvm.interfaces.Readable;
import com.dronff.gvm.memorymanager.Memory;
import com.dronff.gvm.memorymanager.SafeBytes;

import java.util.Arrays;

/**
 * @author: tyf
 * @date: 2022/9/9 17:16
 * @description: todo(只能读写但是不能分配的一块内存空间
 */

public class MiniMemoryImpl extends Memory implements Readable, Writable, Addressed {
    private MiniMemoryImpl(){
        super();

    }
    private MiniMemoryImpl(int size) {
        super(size);
    }

    private MiniMemoryImpl(AllocatableMemory parent, int size, int offset) {
        super(parent, size, offset);
    }

    @Override
    public <T> T readOnly(ReadFunction<T> function) {
        assert function != null;
        if(getMemory() == null && getParent() == null){
            throw new IndexOutOfBoundsException("memory and parent both equals 'NULL'");
        }
        // 如果有父内存 调用父内存的readOnlyChild方法
        if(getParent() != null){
            return getParent().readOnlyChild(function,this);
        }
        return function.read(getMemory());
    }

    @Override
    public <T> T readOnlyChild(ReadFunction<T> function, Memory memory) {
        if(getMemory() == null && getParent() == null){
            throw new IndexOutOfBoundsException("memory and parent both equals 'NULL'");
        }
        if(getParent() != null){
            return getParent().readOnlyChild(function,memory);
        }
        return function.read(Arrays.copyOfRange(getMemory(),memory.getOffset(),getSize()));
    }

    @Override
    public <W> void writeOnly(WriteFunction<W> function) {
        assert function != null;
        if(getMemory() == null && getParent() == null){
            throw new IndexOutOfBoundsException("memory and parent both equals 'NULL'");
        }
        if(getParent() != null){
            getParent().writeOnlyChild(function,this);
            return;
        }
        function.write((W) getMemory());
    }

    @Override
    public <W> void writeOnlyChild(WriteFunction<W> function, Memory memory) {
        if(getMemory() == null && getParent() == null){
            throw new IndexOutOfBoundsException("memory and parent both equals 'NULL'");
        }
        if(getParent() != null){
            getParent().writeOnlyChild(function,memory);
            return;
        }
        /**
         * 给他安全的Bytes
         */
        function.write((W) new SafeBytes(getMemory(),memory));
    }
    public static MiniMemoryBuilder getBuilder(){
        return new MiniMemoryBuilder();
    }

    @Override
    public MiniAddress getAddress() {
        MiniAddress miniAddress = new MiniAddress();
        miniAddress
                .setMemoryHash(getHash())
                .setSize(getSize())
                .setOffset(getOffset());
        return miniAddress;
    }

    public static class MiniMemoryBuilder{
        private MiniMemoryImpl miniMemory;
        private MiniMemoryBuilder(){
            this.miniMemory = new MiniMemoryImpl();
        }
        public MiniMemoryBuilder setSize(int size){
            miniMemory.setSize(size);
            return this;
        }
        public MiniMemoryBuilder setParent(AllocatableMemory parent) throws IllegalAccessException {
            miniMemory.setParent(parent);
            return this;
        }
        public MiniMemoryBuilder setOffset(int offset){
            miniMemory.setOffset(offset);
            return this;
        }
        public MiniMemoryImpl build(){
            return miniMemory;
        }
    }
}
